(module tests-book mzscheme
  
  (provide tests-for-run tests-for-check tests-for-parse)
  ;;;;;;;;;;;;;;;; tests ;;;;;;;;;;;;;;;;
  
  ;; the numbers are skewed from the numbers in the chapter.  We'll have
  ;; to fix this at some point.

  (printf "Loading test file for chapter 6~%")

  (define the-test-suite
 
    '(

      (modules-1 "
         module m 
          interface [u : int] 
          implementation [u = 33]
         import m
         from m take u"
        int 33)

      (modules-2a "
         module m 
          interface [u : int]
          implementation [u = 33 v = 44]
         import m
         from m take u"
        int 33)

      (modules-2b "
         module m 
          interface [u : int] 
          implementation [u = 3 v = 4]
         import m
         from m take v"
        error)

      (modules-3 "
         module m 
          interface [u : bool]
          implementation [u = 33]
         44"
        error)

      (modules-4 "
        module m 
         interface [u : int v : int]  
         implementation [u = 44 v = 33]
        import m
        -(from m take u, from m take v)"
        int 11)

      (modules-5 "
         module m 
          interface [u : int v : int]
          implementation [u = 33]
         import m
         from m take u"
        error)

      (modules-6 "
         module m 
          interface [u : int v : int] 
          implementation [v = 33 u = 44]
         from m take u"
        error)

      (modules-7 "
         module m 
          interface [u : int v : int]  
          implementation [u = 44 v = -(u,33)]
         import m
         -(from m take u, from m take v)"
        int 33)

      (modules-8 "
         module m1 
          interface [u : int] 
          implementation [u = 44]
         module m2 
          interface [v : int] 
          implementation 
           import m1
           [v = -(from m1 take u,11)]
         import m1 
         import m2
         -(from m1 take u, from m2 take v)"
        int)


      ;; no, circular imports is no longer an error
;;       (modules-9 "
;;          module m1 
;;                    interface [v : int] 
;;                    implementation import m2 [v = -(from m2 take v,1)]
;;          module m2 
;;                    interface [v : int] 
;;                    implementation import m1 [v = -(from m1 take v,1)]
;;          44"
;;         error)

      (modules-10 "
         module m1 
          interface 
           [type-abbrev t = int 
            z : t]
          implementation 
           [type t = int
            z = 0]
      import m1
      -(from m1 take z,1)"
        int)


      (modules-11 "
      module m1 
       interface 
        [type-abbrev u = int
         z : u]
       implementation 
        [type u = int
         z = 0]
      import m1
      -(from m1 take z,1)"
        int)


      (modules-12.0 "
      module m1 
       interface 
        [type-abbrev t = int
         z : t]
       implementation 
        [type t = int
         z = 0]
      import m1
      let f = proc (x : from m1 take t) -(x,1)
      in (f 33)"
        int 32)


      (modules-12 "
      module m1 
       interface 
        [type-abbrev t = int
         z : t]
       implementation 
        [type t = int
         z = 0]
      import m1
      proc (x : from m1 take t) -(x,1)"
        (int -> int))



      (modules-13 "
      % a slightly different indentation style
      module m1 
       interface [type-abbrev t = int
                  f : (t -> t)]
       implementation [type t = int
                       f = proc (x : t) -(x,1)]
      import m1
      (from m1 take f 
       33)"
        int)

      (modules-14.0 "
      module m1 
       interface [type-abbrev t = int
                  z : t]
       implementation [type t = int
                       z = 0]
      module m2 
                interface [foo : (from m1 take t -> int)]
                implementation import m1 [foo = proc (x : from m1 take t) x]
      import m1 
      import m2
      from m2 take foo"
        (int -> int))      


      (modules-14.1 "
      module m1 
       interface [type-abbrev t = int
                  z : t]
       implementation [type t = int
                       z = 0]

      module m2 
       interface [foo : (from m1 take t -> int)]
       implementation 
        import m1 
        [foo = proc (x : from m1 take t) x]

   %   import m1
      import m2
      (from m2 take foo  33)"
      int  )

      (modules-14 "
      module m1 
       interface [type-abbrev t = int
                  z : t]
       implementation [type t = int
                       z = 0]
      module m2 
       interface [foo : (from m1 take t -> int)]
       implementation 
        import m1 
        [foo = proc (x : from m1 take t) x]
      import m2
      from m2 take foo"
        (int -> int))

      (modules-15 "
      module m1 
       interface [type-abbrev t = int
                  z : t
                  extra : (t -> t)]
       implementation [type t = int
                       z = 0
                       extra = proc (x : ?) x]
      import m1
      from m1 take extra"
        (int -> int))


      (modules-16 "
        module m1
         interface [type-abbrev t = int
                    z : t
                    check : (t -> bool) ] 
         implementation [type t = int
                         z = 0
                         check = proc(x : t) zero?(x)]
        import m1
        from m1 take z"
        int)


      (modules-17 "
        module m1
          interface [abstract-type t
                     z : t
                     check : (t -> bool) ] 
          implementation [type t = int
                          z = 0
                          check = proc(x : t) zero?(x)]
        import m1
        from m1 take z"
        (from m1 take t))


      (modules-18 "
        module m1
          interface [abstract-type t
                     z : t
                     check : (t -> bool) ] 
          implementation [type t = int
                          z = 0
                          check = proc (x : t) zero?(x)]
        import m1
        -(from m1 take z, 1)"
        error)


      (modules-19 "
        module m1
          interface [abstract-type t
                     z : t
                     check : (t -> bool) ] 
          implementation [type t = int
                          z = 0
                          check = proc (x : t) zero?(x)]
        import m1
        from m1 take check"
        ((from m1 take t) -> bool))   


      (modules-20 "
        module m1
          interface [abstract-type t
                     z : t
                     check : (t -> bool) ] 
          implementation [type t = int
                          z = 0
                          check = proc (x : t) zero?(x)]
        import m1
        let f = from m1 take check
        in let a = from m1 take z
           in (f a)"
        bool)


      (modules-21a "
         module mybool 
          interface [abstract-type t
                     true : t
                     false : t
                     and : (t -> (t -> t))
                     not : (t -> t)
                     to-bool : (t -> bool)]
          implementation [type t = int
                          true = 0
                          false = 1
                          and = proc (x : t) 
                                 proc (y : t)
                                  if zero?(x) then y else false
                          not = proc (x : t) 
                                 if zero?(x) then false else true
                          to-bool = proc (x : t)  
                                     if zero?(x) then zero?(0) else zero?(1)]

         import mybool
         let true = from mybool take true
         in let false = from mybool take false
         in let and = from mybool take and
         in ((and true) false)"
        (from mybool take t))


      (modules-21b "
        module int1
         interface [abstract-type t
                    zero : t
                    succ : (t -> t)
                    pred : (t -> t)
                    is-zero : (t -> bool)]  
         implementation [type t = int
                        zero = 0
                        succ = proc(x : ?) -(x,-5)
                        pred = proc(x : ?) -(x,5)
                        is-zero = proc (x : ?) zero?(x)]

         import int1
         let zero = from int1 take zero
         in let succ = from int1 take succ
         in (succ (succ zero))"
        (from int1 take t))


      (modules-22 "
        module int2
         interface [abstract-type t
                    zero : t
                    succ : (t -> t)
                    pred : (t -> t)
                    is-zero : (t -> bool)]  
         implementation [type t = int
                         zero = 0
                         succ = proc(x : ?) -(x,3)
                         pred = proc(x : ?) -(x,-3)
                         is-zero = proc (x : ?) zero?(x)]

         import int2
         let z = from int2 take zero
         in let s = from int2 take succ
         in (s (s z))"
        (from int2 take t) -6)


      (modules-23 "
        module int2
         interface [abstract-type t
                    zero : t
                    succ : (t -> t)
                    pred : (t -> t)
                    is-zero : (t -> bool)]  
         implementation [type t = int
                         zero = 0
                         succ = proc(x : ?) -(x,3)
                         pred = proc(x : ?) -(x,-3)
                         is-zero = proc (x : ?) zero?(x)
                         ]
         import int2
         let z = from int2 take zero
         in let s = from int2 take succ
         in let p = from int2 take pred
         in let z? = from int2 take is-zero
         in letrec int to-int (x : from int2 take t) =
                       if (z? x) then 0
                          else -((to-int (p x)), -1)
         in (to-int (s (s z)))"
        int 2)


      (modules-24 "
        module int1
         interface [abstract-type t
                    zero : t
                    succ : (t -> t)
                    pred : (t -> t)
                    is-zero : (t -> bool)]  
         implementation [type t = int
                         zero = 0
                         succ = proc(x : ?) -(x,-5)
                         pred = proc(x : ?) -(x,5)
                         is-zero = proc (x : ?) zero?(x)
                         ]
        import int1
        let z = from int1 take zero
        in let s = from int1 take succ
        in let p = from int1 take pred
        in let z? = from int1 take is-zero
        in letrec int to-int (x : from int1 take t) =
                      if (z? x) then 0
                         else -((to-int (p x)), -1)
        in (to-int (s (s z)))"
        int 2)



      (modules-26 "
        module to-int-maker 
         interface
          ((m1 : [abstract-type t
                  zero : t
                  succ : (t -> t)
                  pred : (t -> t)
                  is-zero : (t -> bool)]) 
            => [to-int : (from m1 take t -> int)])
         implementation 
          module-proc 
           (m1 : [abstract-type t
                  zero : t
                  succ : (t -> t)
                  pred : (t -> t)
                  is-zero : (t -> bool)])
           [to-int 
             = let z? = from m1 take is-zero
               in let p = from m1 take pred
               in letrec int to-int (x : from m1 take t) 
                 = if (z? x) 
                   then 0
                   else -((to-int (p x)), -1)
               in to-int]

        module int1
         interface [abstract-type t
                    zero : t
                    succ : (t -> t)
                    pred : (t -> t)
                    is-zero : (t -> bool)]  
         implementation [type t = int
                         zero = 0
                         succ = proc(x : ?) -(x,-2)
                         pred = proc(x : ?) -(x,2)
                         is-zero = proc (x : ?) zero?(x)
                         ]

        module int1-to-int
         interface [to-int : (from int1 take t -> int)]
         implementation  
          import to-int-maker 
          import int1
          (to-int-maker int1)

        import int1
        import int1-to-int
        let two1 = (from int1 take succ
                    (from int1 take succ
                     from int1 take zero))
        in (from int1-to-int take to-int
            two1)"
        int 2)


      (modules-27 "
        module to-int-maker 
         interface 
          ((m1 : [abstract-type t
                  zero : t
                  succ : (t -> t)
                  pred : (t -> t)
                  is-zero : (t -> bool)]) 
           => [to-int : (from m1 take t -> int)])
         implementation 
          module-proc
           (m1 : [abstract-type t
                  zero : t
                  succ : (t -> t)
                  pred : (t -> t)
                  is-zero : (t -> bool)])
           [to-int 
             = let z? = from m1 take is-zero
               in let p = from m1 take pred
                  in letrec int to-int (x : from m1 take t) 
                       = if (z? x) 
                         then 0
                         else -((to-int (p x)), -1)
                     in to-int]

        module int1
         interface [abstract-type t
                    zero : t
                    succ : (t -> t)
                    pred : (t -> t)
                    is-zero : (t -> bool)]  
         implementation [type t = int
                         zero = 0
                         succ = proc(x : ?) -(x,-2)
                         pred = proc(x : ?) -(x,2)
                         is-zero = proc (x : ?) zero?(x)
                         ]

        module int2
         interface [abstract-type t
                    zero : t
                    succ : (t -> t)
                    pred : (t -> t)
                    is-zero : (t -> bool)]  
         implementation [type t = int
                         zero = 0
                         succ = proc(x : ?) -(x,3)
                         pred = proc(x : ?) -(x,-3)
                         is-zero = proc (x : ?) zero?(x)
                         ]

        module int1-to-int
         interface [to-int : (from int1 take t -> int)]
         implementation 
          import int1 
          import to-int-maker
          (to-int-maker int1)

        module int2-to-int
         interface [to-int : (from int2 take t -> int)]
         implementation 
          import int2
          import to-int-maker
          (to-int-maker int2)

        import int1 
        import int1-to-int 
        import int2 
        import int2-to-int

        let s1 = from int1 take succ
        in let z1 = from int1 take zero
        in let to-int1 = from int1-to-int take to-int

        in let s2 = from int2 take succ
        in let z2 = from int2 take zero
        in let to-int2 = from int2-to-int take to-int

        in let two1 = (s1 (s1 z1))
        in let two2 = (s2 (s2 z2))
        in -((to-int1 two1), (to-int2 two2))"
        int 0)

      (modules-27a "
        module to-int-maker 
         interface 
          ((m1 : [abstract-type t
                  zero : t
                  succ : (t -> t)
                  pred : (t -> t)
                  is-zero : (t -> bool)]) 
           => [to-int : (from m1 take t -> int)])
         implementation 
          module-proc
           (m1 : [abstract-type t
                  zero : t
                  succ : (t -> t)
                  pred : (t -> t)
                  is-zero : (t -> bool)])
           [to-int 
             = let z? = from m1 take is-zero
               in let p = from m1 take pred
                  in letrec int to-int (x : from m1 take t) 
                       = if (z? x) 
                         then 0
                         else -((to-int (p x)), -1)
                     in to-int]

        module int1
         interface [abstract-type t
                    zero : t
                    succ : (t -> t)
                    pred : (t -> t)
                    is-zero : (t -> bool)]  
         implementation [type t = int
                         zero = 0
                         succ = proc(x : ?) -(x,-2)
                         pred = proc(x : ?) -(x,2)
                         is-zero = proc (x : ?) zero?(x)
                         ]

        module int2
         interface [abstract-type t
                    zero : t
                    succ : (t -> t)
                    pred : (t -> t)
                    is-zero : (t -> bool)]  
         implementation [type t = int
                         zero = 0
                         succ = proc(x : ?) -(x,3)
                         pred = proc(x : ?) -(x,-3)
                         is-zero = proc (x : ?) zero?(x)
                         ]

        module int1-to-int
         interface [to-int : (from int1 take t -> int)]
         implementation 
          import int1 
          import to-int-maker
          (to-int-maker int1)

        module int2-to-int
         interface [to-int : (from int2 take t -> int)]
         implementation 
          import int2
          import to-int-maker
          (to-int-maker int2)

        import int1 
        import int1-to-int 
        import int2 
        import int2-to-int

        let s1 = from int1 take succ
        in let z1 = from int1 take zero
        in let to-int1 = from int1-to-int take to-int

        in let s2 = from int2 take succ
        in let z2 = from int2 take zero
        in let to-int2 = from int2-to-int take to-int

        in let two1 = (s1 (s1 z1))
        in let two2 = (s2 (s2 z2))
        in -((to-int1 two1), (to-int2 two1))"
        error)

      (table-1 "
        module tables
         interface [abstract-type table
                    empty : table
                    add-to-table : (int -> (int -> (table -> table)))
                    lookup-in-table : (int -> (table -> int))]
         implementation
          [type table = (int -> int)
           type keytype = int
           type valtype = int
           empty = proc (n : int) 0
           add-to-table
            = proc (key : keytype)
               proc (val : valtype)
                proc (saved-table : table)
                 proc (search-key : keytype)
                  if zero?(-(key, search-key)) 
                  then val
                  else (saved-table search-key)
            lookup-in-table 
             = proc (search-key : keytype)
                proc (table : table)
                 (table search-key)]

          import tables
          let empty = from tables take empty
          in let add-binding = from tables take add-to-table
          in let lookup = from tables take lookup-in-table
          in let table1 = (((add-binding 3) 300) empty)
          in let table2 = (((add-binding 4) 400) table1)
          in let table3 = (((add-binding 3) 301) table2)
          in -( ((lookup 4) table3),
                ((lookup 3) table3))
          "
        int
        99)

      (abstype-1 "
        module m1
        interface [abstract-type t
                   z : t
                   check : (t -> bool)] 
        implementation [type t = int
                        z = 11
                        check = proc (x : t) zero?(0)]
        33"
        int
        33)

      (mybool-1 "
        module mybool 
         interface [abstract-type t
                    true : t
                    false : t
                    and : (t -> (t -> t))
                    not : (t -> t)
                    to-bool : (t -> bool)]
         implementation [type t = int
                         true = 1
                         false = 0
                         and = proc (x : t) proc (y : t)
                                    if zero?(x) then false else y
                         not = proc (x : t) if zero?(x) then true else false
                         to-bool = proc (x : t) 
                                        if zero?(x) then zero?(1) else zero?(0)
            ]
         33"
        int)
 
      ))

  (define tests-for-run
    (let loop ((lst the-test-suite))
      (cond
        ((null? lst) '())
        ((= (length (car lst)) 4)
         ;; (printf "creating item: ~s~%" (caar lst))
         (cons
           (list
             (list-ref (car lst) 0)
             (list-ref (car lst) 1)
             (list-ref (car lst) 3))
           (loop (cdr lst))))
        (else (loop (cdr lst))))))

  ;; ok to have extra members in a test-item.
  (define tests-for-check the-test-suite)

  (define tests-for-parse the-test-suite)

  )

